﻿<ComClass(ClsMatrix4Ex.ClassId, ClsMatrix4Ex.InterfaceId, ClsMatrix4Ex.EventsId)>
Public Class ClsMatrix4Ex

#Region "COM GUID"
    ' 这些 GUID 提供此类的 COM 标识 
    ' 及其 COM 接口。若更改它们，则现有的
    ' 客户端将不再能访问此类。
    Public Const ClassId As String = "7c317344-dc9d-4276-a743-81c39840fe51"
    Public Const InterfaceId As String = "95adcdd1-7f92-46e8-9ab5-e02672a4b4df"
    Public Const EventsId As String = "62c5759d-d58b-4f44-ab69-8f4bf1f6ad0f"
#End Region

    ' 可创建的 COM 类必须具有一个不带参数的 Public Sub New() 
    ' 否则， 将不会在 
    ' COM 注册表中注册此类，且无法通过
    ' CreateObject 创建此类。
    Public Sub New()
        MyBase.New()
    End Sub

    ''' <summary>
    ''' 平移矩阵
    ''' https://zhuanlan.zhihu.com/p/96717729
    ''' </summary>
    ''' <param name="oriPt"></param>
    ''' <param name="targetPt"></param>
    Public Function CreateTranslationMatrix(oriPt As ClsPoint3d, targetPt As ClsPoint3d) As Double(,)
        Dim rtn(0 To 3, 0 To 3) As Double
        Dim V = oriPt.GetVector3dTo(targetPt)
        rtn(0, 0) = 1 : rtn(0, 1) = 0 : rtn(0, 2) = 0 : rtn(0, 3) = V.X
        rtn(1, 0) = 0 : rtn(1, 1) = 1 : rtn(1, 2) = 0 : rtn(1, 3) = V.Y
        rtn(2, 0) = 0 : rtn(2, 1) = 0 : rtn(2, 2) = 1 : rtn(2, 3) = V.Z
        rtn(3, 0) = 0 : rtn(3, 1) = 0 : rtn(3, 2) = 0 : rtn(3, 3) = 1
        ' Translation Matrix: move an object by 10,10,0
        ' 1.000000  0.000000  0.000000  10.000000
        ' 0.000000  1.000000  0.000000  10.000000
        ' 0.000000  0.000000  1.000000  0.000000
        ' 0.000000  0.000000  0.000000  1.000000
        Return rtn
    End Function

    ''' <summary>
    ''' 平移矩阵
    ''' https://zhuanlan.zhihu.com/p/96717729
    ''' </summary>
    ''' <param name="v"></param>
    Public Function CreateTranslationMatrixByVector(v As ClsVector3d) As Double(,)
        Dim rtn(0 To 3, 0 To 3) As Double
        rtn(0, 0) = 1 : rtn(0, 1) = 0 : rtn(0, 2) = 0 : rtn(0, 3) = v.X
        rtn(1, 0) = 0 : rtn(1, 1) = 1 : rtn(1, 2) = 0 : rtn(1, 3) = v.Y
        rtn(2, 0) = 0 : rtn(2, 1) = 0 : rtn(2, 2) = 1 : rtn(2, 3) = v.Z
        rtn(3, 0) = 0 : rtn(3, 1) = 0 : rtn(3, 2) = 0 : rtn(3, 3) = 1
        ' Translation Matrix: move an object by 10,10,0
        ' 1.000000  0.000000  0.000000  10.000000
        ' 0.000000  1.000000  0.000000  10.000000
        ' 0.000000  0.000000  1.000000  0.000000
        ' 0.000000  0.000000  0.000000  1.000000
        Return rtn
    End Function
    ''' <summary>
    ''' https://blog.csdn.net/csxiaoshui/article/details/65446125
    ''' </summary>
    ''' <param name="angle"></param>
    ''' <param name="rotationAlisx"></param>
    ''' <returns></returns>
    Public Function CreateRotationMatrix(angle As Double, rotationAlisx As ClsVector3d) As Double(,)
        Dim rtn(0 To 3, 0 To 3) As Double
        Dim V1 = rotationAlisx.UnitVector
        Dim u = V1.X, v = V1.Y, w = V1.Z

        rtn(0, 0) = u ^ 2 + (1 - u ^ 2) * Math.Cos(angle)
        rtn(0, 1) = u * v * (1 - Math.Cos(angle)) - w * Math.Sin(angle)
        rtn(0, 2) = u * w * (1 - Math.Cos(angle)) + v * Math.Sin(angle) : rtn(0, 3) = 0

        rtn(1, 0) = u * v * (1 - Math.Cos(angle)) + w * Math.Sin(angle)
        rtn(1, 1) = v ^ 2 + (1 - v ^ 2) * Math.Cos(angle)
        rtn(1, 2) = v * w * (1 - Math.Cos(angle)) - u * Math.Sin(angle) : rtn(1, 3) = 0

        rtn(2, 0) = u * w * (1 - Math.Cos(angle)) - v * Math.Sin(angle)
        rtn(2, 1) = v * w * (1 - Math.Cos(angle)) + u * Math.Sin(angle)
        rtn(2, 2) = w ^ 2 + (1 - w ^ 2) * Math.Cos(angle) : rtn(2, 3) = 0

        rtn(3, 0) = 0 : rtn(3, 1) = 0 : rtn(3, 2) = 0 : rtn(3, 3) = 1

        ' Rotation Matrix: 45 Degrees about point 5,5,0
        ' 0.70710678118654  -0.70710678118654  0.000000  5.000000
        ' 0.70710678118654  0.70710678118654  0.000000  -2.071068
        ' 0.000000  0.000000  1.000000  0.000000
        ' 0.000000  0.000000  0.000000  1.000000

        Return rtn
    End Function

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="scalingX"></param>
    ''' <param name="scalingY"></param>
    ''' <param name="scalingZ"></param>
    ''' <param name="p"></param>
    ''' <returns></returns>
    Public Function CreateScalingMatrixWithBasePoint(scalingX As Double, scalingY As Double, scalingZ As Double, p As ClsPoint3d) As Double(,)
        Dim mmt = CreateTranslationMatrixByVector(p.GetAsVector3d().NegateVector)
        Dim mmt1 = CreateTranslationMatrixByVector(p.GetAsVector3d())
        Dim mms = CreateScalingMatrix(scalingX, scalingY, scalingZ)
        Return MatrixMultiply(MatrixMultiply(mmt, mms), mmt1)
    End Function

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="angle"></param>
    ''' <param name="rotationAlisx"></param>
    ''' <param name="p"></param>
    ''' <returns></returns>
    Public Function CreateRotationMatrixWithBasePoint(angle As Double, rotationAlisx As ClsVector3d, p As ClsPoint3d) As Double(,)
        Dim mmt = CreateTranslationMatrixByVector(p.GetAsVector3d().NegateVector)
        Dim mmt1 = CreateTranslationMatrixByVector(p.GetAsVector3d())
        Dim mmr = CreateRotationMatrix(angle, rotationAlisx)
        Return MatrixMultiply(MatrixMultiply(mmt, mmr), mmt1)
    End Function


    Public Function CreateScalingMatrix(scalingX As Double, scalingY As Double, scalingZ As Double) As Double(,)
        Dim rtn(0 To 3, 0 To 3) As Double
        rtn(0, 0) = scalingX : rtn(0, 1) = 0 : rtn(0, 2) = 0 : rtn(0, 3) = 0
        rtn(1, 0) = 0 : rtn(1, 1) = scalingY : rtn(1, 2) = 0 : rtn(1, 3) = 0
        rtn(2, 0) = 0 : rtn(2, 1) = 0 : rtn(2, 2) = scalingZ : rtn(2, 3) = 0
        rtn(3, 0) = 0 : rtn(3, 1) = 0 : rtn(3, 2) = 0 : rtn(3, 3) = 1
        ' Scaling Matrix: scale by 10,10 at point 0,0,0
        ' 10.000000  0.000000  0.000000  0.000000
        ' 0.000000  10.000000  0.000000  0.000000
        ' 0.000000  0.000000  10.000000  0.000000
        ' 0.000000  0.000000  0.000000  1.000000
        Return rtn
    End Function
    ''' <summary>
    ''' http://www2.edu-edu.com.cn/lesson_crs78/self/j_0022/soft/ch0605.html
    ''' </summary>
    ''' <param name="a">先变换的矩阵</param>
    ''' <param name="b">后变换的矩阵</param> 
    ''' <returns>矩阵复合</returns> 
    Public Function MatrixMultiply(ByRef a(,) As Double, ByRef b(,) As Double) As Double(,)

        Debug.Assert(a.GetLength(0) = 4 And a.GetLength(1) = 4, "参数a必须是4x4的数组")
        Debug.Assert(b.GetLength(0) = 4 And b.GetLength(1) = 4, "参数b必须是4x4的数组")
        Dim matA As New Matrix4(a), matB As New Matrix4(b)
        Dim c As Matrix4 = matB * matA
        Return c.ToArray()
    End Function
End Class


